import 'dart:ui' as ui;

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:octo_image/octo_image.dart';
import 'package:uikit/utils/image_util/image_convert.dart';
import 'package:uikit/utils/screen_util/size_extension.dart';

import '../../extension/ui_extension.dart';
import '../../uikit.dart';
import '../../utils/image_util/image_util.dart';
import 'default_anchor_widget.dart';

/// 锚点图片

///图片加载方式
enum AnchorImageType {
  asset,
  net,
  //...
}

class DefaultAnchorWidget extends AnchorWidget {
  DefaultAnchorWidget({
    required ui.Offset position,
    this.txt = '',
    bool drawIcon = true,
    int id = 0,
    this.tapCallback,
  }) : super(position, drawIcon: drawIcon, id: id) {
    _initPainter();
  }

  ///tag文本画笔
  late TextPainter textPainter;

  final Function? tapCallback;

  final String txt;

  final Paint _bgPaint = ui.Paint()
    ..color = Colors.black.withOpacity(0.5)
    ..style = PaintingStyle.fill;

  void _initPainter() {
    final List<InlineSpan> children = <InlineSpan>[
      TextSpan(
        text: txt.length > 11 ? '${txt.substring(0, 10)}...' : txt,
      )
    ];
    const TextSpan iconSpace = TextSpan(text: '  ');
    final TextSpan sp = TextSpan(
        text: String.fromCharCode(tagIcon.codePoint),
        style: TextStyle(fontSize: 10.w, color: Colors.white, fontFamily: tagIcon.fontFamily, package: RikiUikit.PACKAGE));
    if (drawIcon) {
      children.insertAll(0, <InlineSpan>[sp, iconSpace]);
    }
    textPainter =
        TextPainter(text: TextSpan(children: children, style: TextStyle(color: Colors.white, fontSize: 11.w)), textDirection: TextDirection.ltr);
  }

  @override
  void onTap() {
    tapCallback?.call();
  }

  @override
  double get space => 6.w;

  @override
  Widget getMarkWidget(BuildContext context) {
    return Container(
      width: 12.w,
      height: 12.w,
      decoration: BoxDecoration(color: Colors.black.withOpacity(0.5), shape: BoxShape.circle),
      child: CustomPaint(
        painter: DefaultTagPainter(this),
      ),
    );
  }

  @override
  ui.Paint getTagBgPint() {
    return _bgPaint;
  }

  @override
  TextPainter getTxtPainter() {
    return textPainter;
  }

  @override
  double get tagCorner => 20.w;

  @override
  double get tagHorizontalPadding => 8.w;

  @override
  double get tagVerticalPadding => 2.w;

  @override
  IconData get tagIcon => Icons.shop;
  // IconData get tagIcon => RikiIcons.shops;

  @override
  double get tagIconSize => 10.w;
}

abstract class AnchorWidget {
  AnchorWidget(this.position, {this.drawIcon = false, this.id = 0}) : assert(position.dx + position.dy <= 200, 'position参数为百分比，取值在1-100之间');

  ///id 标识
  final int id;

  ///用于在stack定位[getMarkWidget]的位置
  ///方位：position的dx,dy等于stack的 left,top的值
  final Offset position;

  double get dxRatio => position.dx / 100;

  double get dyRatio => position.dy / 100;

  bool get markerAtRight => dxRatio > 0.5;

  IconData get tagIcon;

  double get tagIconSize;

  ///是否绘制 tag icon
  final bool drawIcon;

  ///marker和tag的间距
  double get space => 12.w;

  ///icon和文字的间隙
  double get iconSpace => 4.w;

  ///文本垂直边距
  double get tagVerticalPadding;

  ///文本水平边距
  double get tagHorizontalPadding;

  ///文本背景圆角
  double get tagCorner;

  void onTap();

  ///文本画笔
  TextPainter getTxtPainter();

  ///背景画笔
  Paint getTagBgPint();

  ///获取标记widget
  /// * 如一个原点
  Widget getMarkWidget(BuildContext context);

  ///position left 值
  /// * 对应stack.left
  double getLeft(Size imgSize) {
    return imgSize.width * dxRatio;
  }

  ///position top 值
  /// * 对应stack.top
  double getTop(Size imgSize) {
    return imgSize.height * dyRatio;
  }
}

class AnchorImageWidget extends StatefulWidget {
  const AnchorImageWidget({
    Key? key,
    required this.imageUrl,
    required this.anchors,
    required this.imageType,
    this.placeHolderWidget,
    this.customErrorWidget,
    this.width,
    this.height,
    this.cacheKey,
    this.fit = BoxFit.fill,
    this.color,
    this.colorBlendMode = ImageUtil.colorBlendMode,
    this.package,
    this.duration = const Duration(milliseconds: 500),
    this.scaleType = ScaleType.scaleByWidth,
    this.targetWidth,
    this.useOriginImg = true,
    this.scaleRatio = 50,
  }) : super(key: key);

  final String imageUrl;

  final List<AnchorWidget> anchors;

  final AnchorImageType imageType;

  final double? width;

  final double? height;

  final Widget? placeHolderWidget;

  final Widget? customErrorWidget;

  final String? cacheKey;

  final BoxFit fit;

  final Color? color;

  final BlendMode colorBlendMode;

  final String? package;

  final Duration duration;

  final ScaleType scaleType;

  final int? targetWidth;

  final bool useOriginImg;

  final int scaleRatio;

  @override
  State<StatefulWidget> createState() {
    return AnchorImageWidgetState();
  }
}

class AnchorImageWidgetState extends State<AnchorImageWidget> {
  CacheManager get cacheManager => ImageUtil.cacheManager!;

  ScaleType get scaleType => widget.scaleType;

  int get scaleRatio => widget.scaleRatio;

  int get targetWidth => widget.targetWidth ?? 1400;

  String get imageUrl => widget.imageUrl;

  double? get width => widget.width;

  double? get height => widget.height;

  Widget get customHolderWidget => widget.placeHolderWidget ?? RikiEmpty.ui;

  Widget get customErrorWidget => widget.customErrorWidget ?? ImageConvert.retrieveCommonImgErrorWidget(width: width, height: height);

  PlaceholderWidgetBuilder get placeHolderWidget => (context, url) => customHolderWidget;

  LoadingErrorWidgetBuilder get errorWidget => (context, url, error) => customErrorWidget;

  String? get cacheKey => widget.cacheKey;

  BoxFit get fit => widget.fit;

  Color? get color => widget.color;

  BlendMode get colorBlendMode => widget.colorBlendMode;

  Duration get duration => widget.duration;

  String? get package => widget.package;

  ///anchor widget 构建器
  /// * int 构建次数
  ValueNotifier<int> anchorBuilder = ValueNotifier(0);

  Size? imgSize;

  void imgDone(BuildContext ctx) {
    WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
      if (mounted) {
        final RenderObject? ro = ctx.findRenderObject();
        if (ro is RenderBox) {
          imgSize = ro.size;
          anchorBuilder.value++;
        }
      }
    });
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        _wrapImageWidget(),
        Positioned.fill(
            child: ValueListenableBuilder<int>(
                valueListenable: anchorBuilder,
                builder: (ctx, value, child) {
                  return value == 0
                      ? RikiEmpty.ui
                      : Stack(
                          children: _buildAnchorWidgets(),
                        );
                })),
      ],
    );
  }

  int ids = DateTime.now().millisecondsSinceEpoch;

  List<Widget> _buildAnchorWidgets() {
    if (imgSize == null) {
      return const <Widget>[];
    }
    return widget.anchors.map((e) {
      return Positioned(
        left: e.getLeft(imgSize!),
        top: e.getTop(imgSize!),
        child: AnchorRenderWidget(
          child: e.getMarkWidget(context),
          anchorWidget: e,
        ),
      );
    }).toList();
  }

  Widget _wrapImageWidget() {
    switch (widget.imageType) {
      case AnchorImageType.asset:
        return Image.asset(
          imageUrl,
          height: height,
          width: width,
          fit: fit,
          color: color,
          colorBlendMode: colorBlendMode,
          package: package,
          frameBuilder: (ctx, child, v, was) {
            if (v != null) {
              imgDone(ctx);
            }
            return child;
          },
        );
      case AnchorImageType.net:
        return CachedNetworkImage(
          cacheManager: cacheManager,
          imageUrl: imageUrl,
          imageBuilder: (ctx, provider) {
            imgDone(ctx);
            return OctoImage(image: provider);
          },
          placeholder: placeHolderWidget,
          errorWidget: errorWidget,
          width: width,
          height: height,
          fadeInDuration: duration,
          fadeOutDuration: duration,
          cacheKey: cacheKey,
          fit: fit,
          color: color,
          colorBlendMode: colorBlendMode,
        );
    }
  }

  @override
  void initData(BuildContext context) {}
}

class AnchorRenderWidget extends SingleChildRenderObjectWidget {
  const AnchorRenderWidget({Key? key, Widget? child, required this.anchorWidget}) : super(key: key, child: child);

  final AnchorWidget anchorWidget;

  @override
  RenderObject createRenderObject(BuildContext context) {
    return AnchorRenderObject(anchorWidget);
  }
}

class AnchorRenderObject extends RenderProxyBoxWithHitTestBehavior {
  AnchorRenderObject(this.anchorWidget);

  final AnchorWidget anchorWidget;

  TextPainter get txtPainter => anchorWidget.getTxtPainter();

  Paint get bgPaint => anchorWidget.getTagBgPint();

  double? tagWidth;

  @override
  void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
    if (event is PointerDownEvent) {
      anchorWidget.onTap();
    } else {
      super.handleEvent(event, entry);
    }
  }

  @override
  bool hitTest(BoxHitTestResult result, {required ui.Offset position}) {
    bool hitTarget = false;
    tagWidth ??= 0;
    final Size tagSize = Size(size.width + (tagWidth ?? 0), size.height);
    //如果后期tag可以相对marker垂直布局，那么这里的判断条件需要调整
    bool expandCheck() {
      return tagWidth! > 0 ? tagSize.contains(position) : (position.dx > tagWidth! && position.dy > 0 && position.dy < size.height);
    }

    if (size.contains(position) || expandCheck()) {
      hitTarget = true;
      result.add(BoxHitTestEntry(this, position));
      // if (hitTarget || behavior == HitTestBehavior.translucent)
      //   result.add(BoxHitTestEntry(this, position));
    }
    return hitTarget;
  }

  @override
  void layout(Constraints constraints, {bool parentUsesSize = false}) {
    txtPainter.layout();
    super.layout(constraints, parentUsesSize: parentUsesSize);
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    super.paint(context, offset);
    final Size txtSize = txtPainter.size;
    //debugPrint('txt : $size   ${anchorWidget.space}');
    final double tagOffset = anchorWidget.markerAtRight ? -(txtSize.width + anchorWidget.space) : (size.width + anchorWidget.space);
    final Offset bgLT = offset.translate(tagOffset, -anchorWidget.tagVerticalPadding);
    final Offset bgRB = anchorWidget.markerAtRight
        ? offset + Offset(-anchorWidget.space, txtSize.height - anchorWidget.tagVerticalPadding)
        : offset + Offset(anchorWidget.space + size.width + txtSize.width, txtSize.height - anchorWidget.tagVerticalPadding);
    final double tagTranslate = anchorWidget.space + anchorWidget.tagHorizontalPadding;
    //整体偏移
    final Rect bg = Rect.fromPoints(bgLT, bgRB).translate(anchorWidget.markerAtRight ? -tagTranslate : tagTranslate, 0);
    //矩形需要调整
    //final double shiftY = anchorWidget.tagPadding/2;
    context.canvas.drawRRect(
        RRect.fromRectAndRadius(
            bg.inflateXY(anchorWidget.tagHorizontalPadding, anchorWidget.tagVerticalPadding), Radius.circular(anchorWidget.tagCorner))
        //.shift(Offset(0, shiftY))
        ,
        bgPaint);
    //绘制文字
    txtPainter.paint(context.canvas,
        offset.translate(tagOffset, -anchorWidget.tagVerticalPadding).translate(anchorWidget.markerAtRight ? -tagTranslate : tagTranslate, 0));

    tagWidth ??= anchorWidget.markerAtRight ? -(bg.width + anchorWidget.space) : (bg.width + anchorWidget.space);
  }
}

extension AnchorRect on Rect {
  Rect inflateXY(double dx, double dy) {
    return Rect.fromLTRB(left - dx, top - dy, right + dx, bottom + dy);
  }
}
